/*
* Copyright (C) 2014 MediaTek Inc.
* Modification based on code covered by the mentioned copyright
* and/or permission notice(s).
*/
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.freeme.largermode;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.net.Uri;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.util.Log;
import android.webkit.MimeTypeMap;

public final class ImageLoader {

    private static final String LOGTAG = "ImageLoader";

    public static final String JPEG_MIME_TYPE = "image/jpeg";
    public static final int DEFAULT_COMPRESS_QUALITY = 95;

   

    private static final int BITMAP_LOAD_BACKOUT_ATTEMPTS = 5;
    private static final float OVERDRAW_ZOOM = 1.2f;
    private ImageLoader() {}

    /**
     * Returns the Mime type for a Url.  Safe to use with Urls that do not
     * come from Gallery's content provider.
     */
    public static String getMimeType(Uri src) {
        String postfix = MimeTypeMap.getFileExtensionFromUrl(src.toString());
        String ret = null;
        if (postfix != null) {
            ret = MimeTypeMap.getSingleton().getMimeTypeFromExtension(postfix);
        }
        return ret;
    }

    @SuppressWarnings("finally")
	public static String getLocalPathFromUri(Context context, Uri uri) {
        /// M: [BUG.MODIFY] @{
        /*        Cursor cursor = context.getContentResolver().query(uri,
                new String[]{MediaStore.Images.Media.DATA}, null, null, null);
        if (cursor == null) {
            return null;
        }
        int index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(index);*/
        // fix cursor leak.
        Cursor cursor = null;
        String path = null;
        try {
            cursor = context.getContentResolver().query(uri,
                    new String[]{MediaStore.Images.Media.DATA}, null, null, null);
            if (cursor == null) {
                return null;
            }
            int index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            path = cursor.getString(index);
        } catch (IllegalArgumentException e) {
            Log.e(LOGTAG, "Exception at getLocalPathFromUri()", e);
        } finally {
            if (cursor != null) {
                cursor.close();
            }
            return path;
        }
        /// @}
    }

    /**
     * Returns the image's orientation flag.  Defaults to ORI_NORMAL if no valid
     * orientation was found.
     */
   

    /**
     * Returns the rotation of image at the given URI as one of 0, 90, 180,
     * 270.  Defaults to 0.
     */
   
    /**
     * Takes an orientation and a bitmap, and returns the bitmap transformed
     * to that orientation.
     */
  
    /**
     * Returns the bitmap for the rectangular region given by "bounds"
     * if it is a subset of the bitmap stored at uri.  Otherwise returns
     * null.
     */
    public static Bitmap loadRegionBitmap(Context context,
                                          Uri uri, BitmapFactory.Options options,
                                          Rect bounds) {
        InputStream is = null;
        int w = 0;
        int h = 0;
        if (options.inSampleSize != 0) {
            return null;
        }
        try {
            is = context.getContentResolver().openInputStream(uri);
            BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
            Rect r = new Rect(0, 0, decoder.getWidth(), decoder.getHeight());
            w = decoder.getWidth();
            h = decoder.getHeight();
            Rect imageBounds = new Rect(bounds);
            // return null if bounds are not entirely within the bitmap
            if (!r.contains(imageBounds)) {
                imageBounds.intersect(r);
                bounds.left = imageBounds.left;
                bounds.top = imageBounds.top;
            }
           
            Bitmap bitmap = decoder.decodeRegion(imageBounds, options);
           
            return bitmap;
        } catch (FileNotFoundException e) {
            Log.e(LOGTAG, "FileNotFoundException for " + uri, e);
        } catch (IOException e) {
            Log.e(LOGTAG, "FileNotFoundException for " + uri, e);
        } catch (IllegalArgumentException e) {
            Log.e(LOGTAG, "exc, image decoded " + w + " x " + h + " bounds: "
                    + bounds.left + "," + bounds.top + " - "
                    + bounds.width() + "x" + bounds.height() + " exc: " + e);
        } finally {
          
        }
        return null;
    }

    /**
     * Returns the bounds of the bitmap stored at a given Url.
     */
    public static Rect loadBitmapBounds(Context context, Uri uri) {
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        loadBitmap(context, uri, o);
        return new Rect(0, 0, o.outWidth, o.outHeight);
    }

    /**
     * Loads a bitmap that has been downsampled using sampleSize from a given url.
     */
    public static Bitmap loadDownsampledBitmap(Context context, Uri uri, int sampleSize) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inMutable = true;
        options.inSampleSize = sampleSize;
        /// M: [DEBUG.MODIFY] @{
        /*  return loadBitmap(context, uri, options);*/
        // remove alpha channel of png to avoid overlay display
        return replaceBitmapBgColor(loadBitmap(context, uri, options), 0xFF000000, true);
        /// @}
    }

    /**
     * Returns the bitmap from the given uri loaded using the given options.
     * Returns null on failure.
     */
    /// M: [BUG.MARK] @{
    /*    public static Bitmap loadBitmap(Context context, Uri uri, BitmapFactory.Options o) {
        if (uri == null || context == null) {
            throw new IllegalArgumentException("bad argument to loadBitmap");
        }
        InputStream is = null;
        try {
            is = context.getContentResolver().openInputStream(uri);
            return BitmapFactory.decodeStream(is, null, o);
        } catch (FileNotFoundException e) {
            Log.e(LOGTAG, "FileNotFoundException for " + uri, e);
        } finally {
            Utils.closeSilently(is);
        }
        return null;
    }*/
    /// @}

    public static Bitmap loadBitmap(Context context, Uri uri, BitmapFactory.Options o) {
        if (uri == null || context == null) {
            throw new IllegalArgumentException("bad argument to loadBitmap");
        }
        Log.i(LOGTAG, "uri = " + uri);
        InputStream is = null;
        Bitmap result = null;
        ///M : added for Drm image decode. @{
        android.database.Cursor c = null;
        int index_Drm = -1;
        boolean isDrm = false;
        String filePath = null;
        try {
            c = context.getContentResolver().query(uri, new String[] { Images.ImageColumns.DATA}, null, null, null);
            if (c != null && c.moveToFirst()) {
                 index_Drm = c.getInt(0);
                 filePath = c.getString(1);
            }
        } catch (IllegalStateException e) {
            Log.e(LOGTAG, "Exception when trying to fetch IS_DRM and DATA info", e);
        }  finally {
            if (c != null) {
                c.close();
            }
        }
        if (index_Drm == 1) {
            isDrm = true;
        }
        try {
            if (null != uri && null != uri.getPath() && isDrm) {
                //check if this file is drm and can get decrypted buffer
            	  result=BitmapFactory.decodeFile(filePath);
              /*  byte[] buffer = forceDecryptFile(filePath, false);
                if (buffer != null) {
                    result = BitmapFactory.decodeByteArray(buffer, 0, buffer.length, o);
                } else {
                    return null;
                }*/
            	
            } else {
        /// @}
            is = context.getContentResolver().openInputStream(uri);
            result = BitmapFactory.decodeStream(is, null, o);
            /// M: wbmp bitmap format is index8 ,and the format do not support BitmapFactory resize;
            // So We should resize the bitmap for avoid out of memory.
            if (result != null && null == result.getConfig()) {
                result = resizeBitmapByScale(result, 1.0f / o.inSampleSize, true);
            }
            /// @}
            }
            return result;
        } catch (FileNotFoundException e) {
            Log.e(LOGTAG, "FileNotFoundException for " + uri, e);
        } finally {
            
        }
        return null;
    }

    /**
     * Loads a bitmap at a given URI that is downsampled so that both sides are
     * smaller than maxSideLength. The Bitmap's original dimensions are stored
     * in the rect originalBounds.
     *
     * @param uri URI of image to open.
     * @param context context whose ContentResolver to use.
     * @param maxSideLength max side length of returned bitmap.
     * @param originalBounds If not null, set to the actual bounds of the stored bitmap.
     * @param useMin use min or max side of the original image
     * @return downsampled bitmap or null if this operation failed.
     */
    public static Bitmap loadConstrainedBitmap(Uri uri, Context context, int maxSideLength,
            Rect originalBounds, boolean useMin) {
        if (maxSideLength <= 0 || uri == null || context == null) {
            throw new IllegalArgumentException("bad argument to getScaledBitmap");
        }
        // Get width and height of stored bitmap
        Rect storedBounds = loadBitmapBounds(context, uri);
        if (originalBounds != null) {
            originalBounds.set(storedBounds);
        }
        int w = storedBounds.width();
        int h = storedBounds.height();

        // If bitmap cannot be decoded, return null
        if (w <= 0 || h <= 0) {
            return null;
        }

        // Find best downsampling size
        int imageSide = 0;
        if (useMin) {
            imageSide = Math.min(w, h);
        } else {
            imageSide = Math.max(w, h);
        }
        int sampleSize = 1;
        while (imageSide > maxSideLength) {
            imageSide >>>= 1;
            sampleSize <<= 1;
        }

        // Make sure sample size is reasonable
        if (sampleSize <= 0 ||
                0 >= (int) (Math.min(w, h) / sampleSize)) {
            return null;
        }
        return loadDownsampledBitmap(context, uri, sampleSize);
    }

    /**
     * Loads a bitmap at a given URI that is downsampled so that both sides are
     * smaller than maxSideLength. The Bitmap's original dimensions are stored
     * in the rect originalBounds.  The output is also transformed to the given
     * orientation.
     *
     * @param uri URI of image to open.
     * @param context context whose ContentResolver to use.
     * @param maxSideLength max side length of returned bitmap.
     * @param orientation  the orientation to transform the bitmap to.
     * @param originalBounds set to the actual bounds of the stored bitmap.
     * @return downsampled bitmap or null if this operation failed.
     */
    

    public static Bitmap getScaleOneImageForPreset(Context context,
                                                   Uri uri, Rect bounds,
                                                   Rect destination) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inMutable = true;
        if (destination != null) {
            int thresholdWidth = (int) (destination.width() * OVERDRAW_ZOOM);
            if (bounds.width() > thresholdWidth) {
                int sampleSize = 1;
                int w = bounds.width();
                while (w > thresholdWidth) {
                    sampleSize *= 2;
                    w /= sampleSize;
                }
                options.inSampleSize = sampleSize;
            }
        }
        return loadRegionBitmap(context,  uri, options, bounds);
    }

    /**
     * Loads a bitmap that is downsampled by at least the input sample size. In
     * low-memory situations, the bitmap may be downsampled further.
     */
    public static Bitmap loadBitmapWithBackouts(Context context, Uri sourceUri, int sampleSize) {
        boolean noBitmap = true;
        int num_tries = 0;
        if (sampleSize <= 0) {
            sampleSize = 1;
        }
        Bitmap bmap = null;
        while (noBitmap) {
            try {
                // Try to decode, downsample if low-memory.
                bmap = loadDownsampledBitmap(context, sourceUri, sampleSize);
                noBitmap = false;
            } catch (java.lang.OutOfMemoryError e) {
                // Try with more downsampling before failing for good.
                if (++num_tries >= BITMAP_LOAD_BACKOUT_ATTEMPTS) {
                    throw e;
                }
                bmap = null;
                System.gc();
                sampleSize *= 2;
            }
        }
        return bmap;
    }

    /**
     * Loads an oriented bitmap that is downsampled by at least the input sample
     * size. In low-memory situations, the bitmap may be downsampled further.
     */
    public static Bitmap loadOrientedBitmapWithBackouts(Context context, Uri sourceUri,
            int sampleSize) {
        Bitmap bitmap = loadBitmapWithBackouts(context, sourceUri, sampleSize);
        if (bitmap == null) {
            return null;
        }
        //int orientation = getMetadataOrientation(context, sourceUri);
       // bitmap = orientBitmap(bitmap, orientation);
        return bitmap;
    }

    /**
     * Loads bitmap from a resource that may be downsampled in low-memory situations.
     */
    public static Bitmap decodeResourceWithBackouts(Resources res, BitmapFactory.Options options,
            int id) {
        boolean noBitmap = true;
        int num_tries = 0;
        if (options.inSampleSize < 1) {
            options.inSampleSize = 1;
        }
        // Stopgap fix for low-memory devices.
        Bitmap bmap = null;
        while (noBitmap) {
            try {
                // Try to decode, downsample if low-memory.
                bmap = BitmapFactory.decodeResource(
                        res, id, options);
                noBitmap = false;
            } catch (java.lang.OutOfMemoryError e) {
                // Retry before failing for good.
                if (++num_tries >= BITMAP_LOAD_BACKOUT_ATTEMPTS) {
                    throw e;
                }
                bmap = null;
                System.gc();
                options.inSampleSize *= 2;
            }
        }
        return bmap;
    }

/// M: [BUG.MARK] @{
/*    public static XMPMeta getXmpObject(Context context) {
        try {
            InputStream is = context.getContentResolver().openInputStream(
                    MasterImage.getImage().getUri());
            return XmpUtilHelper.extractXMPMeta(is);
        } catch (FileNotFoundException e) {
            return null;
        }
    }*/
/// @}

   

    /**
     * Determine if this is a light cycle 360 image
     *
     * @return true if it is a light Cycle image that is full 360
     */
   

  
    

    // ********************************************************************
    // *                             MTK                                   *
    // ********************************************************************

    //replace Bitmap's back ground with specified color
    public static Bitmap replaceBitmapBgColor(Bitmap b, int color,
                                              boolean recycleInput) {
        if (null == b) return null;
        if (b.getConfig() == Bitmap.Config.RGB_565) {
            Log.i(LOGTAG, "replaceBitmapBgColor:Bitmap has no alpha, no bother");
            return b;
        }
        //Bitmap has alpha channel, and should be replace its background color
        //1,create a new bitmap with same dimension and ARGB_8888
        if (b.getWidth() <= 0 || b.getHeight() <= 0) {
            Log.w(LOGTAG, "replaceBitmapBgColor:invalid Bitmap dimension");
            return b;
        }
        Bitmap b2 = null;
        try {
            b2 = Bitmap.createBitmap(b.getWidth(),
                     b.getHeight(), Bitmap.Config.ARGB_8888);
        } catch (OutOfMemoryError e) {
            Log.e(LOGTAG, "failed to create new bitmap for replacing gif background: ", e);
            return b;
        }
        // framework handled out-of-memory exception will lead to null b2
        if (b2 == null) {
            return b;
        }

        //2,create Canvas to encapulate new Bitmap
        Canvas canvas = new Canvas(b2);
        //3,draw background color
        canvas.drawColor(color);
        //4,draw original Bitmap on background
        canvas.drawBitmap(b, new Matrix(), null);
        //5,recycle original Bitmap if needed
        if (recycleInput) {
            b.recycle();
            b = null;
        }
        //6,return the output Bitmap
        return b2;
    }
    // add for resize bitmap
    public static Bitmap resizeBitmapByScale(
            Bitmap bitmap, float scale, boolean recycle) {
        int width = Math.round(bitmap.getWidth() * scale);
        int height = Math.round(bitmap.getHeight() * scale);
        // fix certain wbmp no thumbnail issue.@{
        if (width < 1 || height < 1) {
            Log.i(LOGTAG, "scaled width or height < 1, no need to resize");
            return bitmap;
        }
        if (width == bitmap.getWidth()
                && height == bitmap.getHeight()) return bitmap;
        Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
        Canvas canvas = new Canvas(target);
        canvas.scale(scale, scale);
        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
        canvas.drawBitmap(bitmap, 0, 0, paint);
        if (recycle) bitmap.recycle();
        return target;
    }


    // add for resize bitmap
    private static Bitmap.Config getConfig(Bitmap bitmap) {
        Bitmap.Config config = bitmap.getConfig();
        if (config == null) {
            config = Bitmap.Config.ARGB_8888;
        }
        return config;
    }

   

}
